package network;

import gui.MainWindow;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

import tool.Message;

public class ThreadEcouteServeur extends Thread {

	private Socket socket;
	private MainWindow window;
	private Connector connector;
	private boolean disconnected;
	
	public ThreadEcouteServeur(Socket socket, MainWindow window, Connector connector) {
		
		this.socket = socket;
		this.window = window;
		this.connector = connector;
	}
	
	@Override
	public void run() {
		
		BufferedReader breader = null;
		String message_recu;
		disconnected = false;
		
		try {
			breader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			
			while (!disconnected) {
				
				try {
					message_recu = Message.readMessage(breader);
				
					if (message_recu != null && !"".equals(message_recu)) {
						System.out.println("Message recu du serveur :\n -> " + message_recu + "\n");
						
						parser(message_recu);
					}
					else {
						System.out.println("Message vide ou null recu du serveur, déconnexion ...\n");
						disconnected = true;
					}
				}
				catch (IOException e) {
					System.out.println("Problème dans readMessage.\n");
					disconnected = true;
				}
			}
			
		} catch (IOException e1) {
			e1.getMessage();
		}
		finally {
			disconnect(breader);
		}
	}
	
	private void disconnect(BufferedReader breader) {
		System.out.println("Déconnexion écoute client.\n");
		
		if (breader != null) {
			try {
				breader.close();
			} catch (IOException e) {
				System.out.println("BufferedReader déjà fermé ?\n");
				e.getMessage();
			}
		}
		
		connector.disconnect();
	}
	
	private void parser(String message) {
		
		String[] message_analyse = message.trim().split("/");
		
		for (int i = 0; i < message_analyse.length; i++)
			message_analyse[i] = message_analyse[i].trim();
		
		if (message_analyse.length >= 1) {
			
			switch (message_analyse[0]) {
			
				case "WELCOME":
					if (message_analyse.length >= 2 && !"".equals(message_analyse[1]))
						welcomeBro(message_analyse[1]);
					break;
					
				case "ACCESSDENIED":
					connectionRejected();
					break;
					
				case "SPECTATOR":
					spectatorValidated();
					break;
			
				case "CONNECTED":
					if (message_analyse.length >= 2 && !"".equals(message_analyse[1]))
						userConnected(message_analyse[1]);
					break;
					
				case "EXITED":
					if (message_analyse.length >= 2 && !"".equals(message_analyse[1]))
						userExited(message_analyse[1]);
					break;
					
				case "NEW_ROUND":
					if (message_analyse.length >= 4
							&& !"".equals(message_analyse[2])
							&& !"".equals(message_analyse[3]))
						newRoundStarted(message_analyse[2], message_analyse[3]);
					else if (message_analyse.length == 3
								&& !"".equals(message_analyse[2]))
							newRoundStarted(message_analyse[2], null);
					break;
					
				case "GUESSED":
					if (message_analyse.length >= 3
							&& !"".equals(message_analyse[1])
							&& !"".equals(message_analyse[2]))
						essaiMot(message_analyse[2], message_analyse[1]);
					break;
					
				case "WORD_FOUND":
					if (message_analyse.length >= 2
							&& !"".equals(message_analyse[1]))
						motTrouveParUnJoueur(message_analyse[1]);
					break;
					
				case "WORD_FOUND_TIMEOUT":
					if (message_analyse.length >= 2
							&& !"".equals(message_analyse[1]))
						motTrouveDebutCompteARebourd(message_analyse[1]);
					break;
					
				case "END_ROUND":
					if (message_analyse.length >= 3
							&& !"".equals(message_analyse[2]))
						finDuRound((!"".equals(message_analyse[1]) ? null : message_analyse[1]), message_analyse[2]);
					break;
					
				case "SCORE_ROUND":
					// Au moins 2 joueurs, donc au moins 5 mots
					if (message_analyse.length >= 5) {
						List<String> scores = new ArrayList<String>();
						
						for (int i = 1; i < message_analyse.length; i++) {
							scores.add(message_analyse[i]);
						}
						
						scoreRound(scores);
					}
					break;
					
				case "LISTEN":
					if (message_analyse.length >= 3
							&& !"".equals(message_analyse[1])
							&& !"".equals(message_analyse[2]))
						receiveTchat(message_analyse[1], message_analyse[2]);
					break;
					
				case "LINE":
					if (message_analyse.length >= 9) {
						
						boolean correctParams = true;
						
						for (int i = 1; i < 9; i++) {
							if ("".equals(message_analyse[i])) {
								correctParams = false;
								break;
							}
						}
						
						if (correctParams) {
							newLineFromServer( message_analyse[1], message_analyse[2], message_analyse[3], message_analyse[4],
									message_analyse[5], message_analyse[6], message_analyse[7], message_analyse[8]);
						}
					}
					break;
					
				case "COURBE":					
					if (message_analyse.length >= 13) {
						
						boolean correctParams = true;
						
						for (int i = 1; i < 13; i++) {
							if ("".equals(message_analyse[i])) {
								correctParams = false;
								break;
							}
						}
						
						if (correctParams) {
							newCourbeFromServer( message_analyse[1], message_analyse[2], message_analyse[3], message_analyse[4],
									message_analyse[5], message_analyse[6], message_analyse[7], message_analyse[8],
									message_analyse[9], message_analyse[10], message_analyse[11], message_analyse[12]);
						}
					}
					
					break;
					
				default:
					System.out.println("Message inconnu, non traite ...\n");
					break;
			}
		}
	}
	
	
	
	
	
	/******************** Events serveur ********************/
	// Pas de probleme de synchro sur l'UI grace a EventQueue
	
	
	/**
	 * Un nouvel utilisateur s'est connecte au serveur
	 */
	private void userConnected(String pseudo_recu) {
		
		String pseudo = window.getCurrentPseudo();
		
		if (pseudo != null && !pseudo.equals(pseudo_recu)) {
			window.userConnected(pseudo_recu);
		}
		else {
			System.out.println("Oui oui, je suis connecté, je sais ...");
		}
	}
	
	
	/**
	 * Un utilisateur s'est deconnecte du serveur
	 */
	private void userExited(String pseudo_recu) {
		
		window.userExited(pseudo_recu);
	}
	
	
	/**
	 * Le pseudo du joueur (non logué) a bien été accepté
	 */
	private void welcomeBro(String pseudo_recu) {
		
		window.welcomeToTheGame(pseudo_recu);
	}
	
	
	/**
	 * Connexion au serveur impossible :
	 * pseudo invalide (déjà pris dans le cas d'un sans-compte, ou dans le cas d'un compte : pseudo non correct, ou mdp non correct)
	 * ou encore partie déjà commencée (2nde version, mise en spectateur forcée)
	 * impossible de le savoir avec ce protocole ...
	 */
	private void connectionRejected() {
		
		System.out.println("Connexion rejetee ...\n");
		
		/**
		 * On déconnecte proprement et on quitte l'application
		 */
		disconnected = true;
		
		window.accessDenied();
	}
	
	
	/**
	 * Un nouveau round est déclenché
	 */
	private void newRoundStarted(String dessinateur_pseudo, String mot) {
		window.newRound(dessinateur_pseudo, mot);
	}
	
	
	/**
	 * Un message de tchat reçu
	 */
	private void receiveTchat(String sender_pseudo, String message) {
		window.tchatMessage(sender_pseudo, message);
	}
	
	
	/**
	 * Mot tenté mais non correct
	 */
	private void essaiMot(String sender_pseudo, String mot_fail) {
		window.essaiMot(sender_pseudo, mot_fail);
	}
	
	
	/**
	 * Un joueur a trouvé le mot
	 */
	private void motTrouveParUnJoueur(String pseudo_finder) {
		window.motTrouve(pseudo_finder);
	}
	
	
	/**
	 * Le compte à rebourd commence suite au fait qu'un joueur a trouvé le mot
	 */
	private void motTrouveDebutCompteARebourd(String timeout) {
		try {
			window.timeoutStarted(Integer.parseInt(timeout));
		}
		catch (NumberFormatException e) {
			System.out.println(e.getMessage());
		}
	}
	
	
	/**
	 * Nouvelle courbe à créer
	 */
	private void newCourbeFromServer(String x1, String y1, String x2, String y2, String x3, String y3, String x4, String y4, String r, String g, String b, String s) {
		
		try {
			window.newCourbe(Integer.parseInt(x1), Integer.parseInt(y1),
					Integer.parseInt(x2), Integer.parseInt(y2),
					Integer.parseInt(x3), Integer.parseInt(y3),
					Integer.parseInt(x4), Integer.parseInt(y4),
					Integer.parseInt(r), Integer.parseInt(g), Integer.parseInt(b),
					Integer.parseInt(s));
		}
		catch (NumberFormatException e) {
			System.out.println(e.getMessage());
		}
	}
	
	
	/**
	 * Nouvelle ligne à créer
	 */
	private void newLineFromServer(String x1, String y1, String x2, String y2, String r, String g, String b, String s) {
		
		try {
			window.newLine(Integer.parseInt(x1), Integer.parseInt(y1),
					Integer.parseInt(x2), Integer.parseInt(y2),
					Integer.parseInt(r), Integer.parseInt(g), Integer.parseInt(b),
					Integer.parseInt(s));
		}
		catch (NumberFormatException e) {
			System.out.println(e.getMessage());
		}
	}
	
	
	/**
	 * Fin d'un round
	 */
	private void finDuRound(String pseudo_winner, String mot_a_trouver) {
		System.out.println("Fin du round\n");
		window.finDuRound(pseudo_winner, mot_a_trouver);
	}
	
	
	/**
	 * Score du round
	 */
	private void scoreRound(List<String> scores) {
		window.scoreRound(scores);
	}
	
	
	/**
	 * Mode spectateur activé
	 */
	private void spectatorValidated() {
		window.spectatorValidated();
	}
}
